主題
=======

主題是一個在 Web 應用程式裡制定網頁外觀的系統方式。通過採用一個新的主題，網頁應用程式的整體外觀可以及時和戲劇性的改變。

在 Yii，每個主題由一個目錄代表，包含視圖檔案，佈局檔案和相關的資源檔案，如圖片， CSS檔案，JavaScript 檔案等。主題的名字就是他的目錄名字。全部主題都放在在同一目錄 `WebRoot/themes` 下 。在任何時候，只有一個主題可以被啟動。

> 提示：預設的主題根目錄 `WebRoot/themes` 可被配置成其他的。只需要配置 [themeManager|CWebApplication::themeManager] 應用程式元件的屬性 [basePath|CThemeManager::basePath] 和 [baseUrl|CThemeManager::baseUrl] 為你所要的值。

要啟動一個主題，設置 Web 應用程式的屬性 [theme|CWebApplication::theme] 為你所要的名字。可以在 [application configuration](/doc/guide/basics.application#application-configuration)中配置或者在執行過程中在控制器的動作裡面修改。

> 註：主題名稱是區分大小寫的。如果您嘗試啟動一個不存在的主題，`Yii::app()->theme` 將返回 `null`。

主題目錄裡面內容的組織方式和 [application base path](/doc/guide/basics.application#application-base-directory)目錄下的組織方式一樣。例如，所有的視圖檔案必須位於 `views` 下 ，佈局視圖檔案在 `views/layouts` 下 ，系統視圖檔案在 `views/system` 下。例如，如果我們要替換 `PostController` 的 `create` 視圖檔案為 `classic` 主題，我們將儲存新的視圖檔案為 `WebRoot/themes/classic/views/post/create.php`。

對於在 [module](/doc/guide/basics.module) 裡面的控制器視圖檔案，相應主題視圖檔案將被放在 `views` 目錄下。例如，如果上述的 `PostController` 是在一個名為 `forum` 的模組裡 ，我們應該儲存`create` 視圖 檔案為 `WebRoot/themes/classic/views/forum/post/create.php`。如果 `forum` 模組巢狀在另一個名為 `support` 模組裡 ，那麼視圖檔案應為 `WebRoot/themes/classic/views/support/forum/post/create.php`。

> 註：由於 `views` 目錄可能包含安全敏感資料，應當配置以防止被網絡使用者存取。

當我們調用 [render|CController::render] 或 [renderPartial|CController::renderPartial]顯示視圖，相應的視圖檔案以及佈局檔案將在當前啟動的主題裡尋找。如果發現，這些檔案將被呈現。否則，就後退到 [viewPath|CController::viewPath]和[layoutPath|CWebApplication::layoutPath] 所指定的預設位置尋找。

> 提示：在一個主題的視圖，我們經常需要鏈接其他主題資源檔案。例如，我們可能要顯示一個在主題下 `images` 目錄裡的圖像檔案。使用當前啟動主題的 [baseUrl|CTheme::baseUrl] 屬性，我們就可以為此圖像檔案產生如下 URL，

> ~~~
> [php]
> Yii::app()->theme->baseUrl . '/images/FileName.gif'
> ~~~
>

下面的範例是一個擁有兩個主題的應用程式的目錄結構。

~~~
WebRoot/
	assets
	protected/
		.htaccess
		components/
		controllers/
		models/
		views/
			layouts/
				main.php
			site/
				index.php
	themes/
		basic/
			views/
				.htaccess
				layouts/
					main.php
				site/
					index.php
		fancy/
			views/
				.htaccess
				layouts/
					main.php
				site/
					index.php
~~~

在應用程式配置中，如果我們設置

~~~
[php]
return array(
	'theme'=>'basic',
	......
);
~~~

那麼 `basic` 主題將被啟用，表示應用程式的佈局將會使用 `themes/basic/views/layouts`，而 index 視圖則是使用 `themes/basic/views/site`。如果視圖檔案不存在主題裡，他會回到 `protected/views` 目錄來尋找。


主題小工具
---------------

版本 1.1.5 後，小工具的視圖也可以主題化。特別是，當我們調用 [CWidget::render()] 來呈現小工具視圖，Yii 會嘗試搜尋在主題目錄下尋找小工具的視圖檔案。

想把一個 `Foo` 小工具的視圖 `xyz` 主題化，我們應該先建立一個目錄叫做 `Foo`（跟小工具同） 在當前啟動的主題視圖目錄。如果一個小工具置於命名空間裡（PHP 5.3.0 以上），像是 `\app\widgets\Foo`，我們應建議一個叫做 `app_widgets_Foo` 的目錄。就是，我們用底線置換了命名空間的分隔符號。

接下來建立一個視圖檔案叫做 `xyz.php` 在新建立的目錄下。最後，我們應該就會有一個檔案 `themes/basic/views/Foo/xyz.php`，將會被小工具用來置換原本的視圖，如果當前的主題是 `basic`。


全域地客製化小工具
----------------------------

> Note|注意: 這功能版本 1.1.3 才支援。

當使用一個第三方或是 Yii 提供的小工具，我們通常需要客製化來符合特殊需求。例如，我們可能會想要改變 [CLinkPager::maxButtonCount] 的值由 10（預設） 變 5。我們可以透過調用 [CBaseController::widget] 來建立小工具時，給定初始化的屬性值來完成。然而，如果我們使用 [CLinkPager]且必須重複在每個地方使用相同的客製化，它將變得很麻煩。

~~~
[php]
$this->widget('CLinkPager', array(
	'pages'=>$pagination,
    'maxButtonCount'=>5,
    'cssFile'=>false,
));
~~~

使用這個全域的小工具客製化功能，我們只需要在一個地方指定這些初始化的值，例如，應用程式配置。這會讓客製化的小工具更好管理。

使用全域的小工具客製化功能，我們需要設定 [widgetFactory|CWebApplication::widgetFactory] 如下：

~~~
[php]
return array(
    'components'=>array(
        'widgetFactory'=>array(
            'widgets'=>array(
                'CLinkPager'=>array(
                    'maxButtonCount'=>5,
                    'cssFile'=>false,
                ),
                'CJuiDatePicker'=>array(
                    'language'=>'ru',
                ),
            ),
        ),
    ),
);
~~~

上述，我們藉由設定 [CWidgetFactory::widgets] 屬性來指定全域小工具客製化給 [CLinkPager] 和 [CJuiDatePicker]。需要注意的是每個小工具的全域客製化是儲存成鍵-值配對的陣列，鍵代表小工具類別的名稱，而值則是屬性的初始化陣列值。

現在，不論何時我們要建立一個 [CLinkPager] 小工具在一個視圖，上述屬性會被賦予給小工具，然後我們只需要如下的方式來建立這個小工具：

~~~
[php]
$this->widget('CLinkPager', array(
	'pages'=>$pagination,
));
~~~

如果需要，我們也可以覆蓋初始化的屬性值。例如，如果某些視圖我們想要設定 `maxButtonCount` 成為 2，我們可以：

~~~
[php]
$this->widget('CLinkPager', array(
	'pages'=>$pagination,
	'maxButtonCount'=>2,
));
~~~


外表
----

> Note|注意: 外表功能從版本 1.1.0 開始支援。

當使用一個主題時，我們可以快速的改變一個視圖的外關，我們可以使用外表來有系統地客製化視圖裡使用的 [widgets](/doc/guide/basics.view#widget) 的外觀。

一個外表是一個名稱-值配對的陣列，可以被用來初始化小工具的屬性。一個外表屬於一個小工具類別，一個小工具還可以藉由不同的外表名稱還擁有許多外表。例如，我們可以有一個小工具 [CLinkPager] 的外表而且名稱是 `classic`。

為了使用外表功能，首先必須修改應用程式的配置，設定 [CWidgetFactory::enableSkin] 屬性為 true 給 `widgetFactory` 應用程式元件：

~~~
[php]
return array(
    'components'=>array(
        'widgetFactory'=>array(
            'enableSkin'=>true,
        ),
    ),
);
~~~

請注意，在版本 1.1.3 之前，你必須用下述的配置來開啟小工具外表功能：

~~~
[php]
return array(
    'components'=>array(
        'widgetFactory'=>array(
            'class'=>'CWidgetFactory',
        ),
    ),
);
~~~

然後，就建立我們需要的外表。一個儲存在 PHP 腳本檔案的外表屬於那些具有相同名稱的一個小工具類別。預設上，這些外表檔案被放置在 `protected/views/skins` 下。如果你想要放在不同的資料夾下，你可以設定 `widgetFactory` 元件的屬性 `skinPath` 。例如，我們可以在 `protected/views/skins` 建立一個名叫 `CLinkPager.php` 檔案，內容如下，

~~~
[php]
<?php
return array(
    'default'=>array(
        'nextPageLabel'=>'&gt;&gt;',
        'prevPageLabel'=>'&lt;&lt;',
    ),
    'classic'=>array(
        'header'=>'',
        'maxButtonCount'=>5,
    ),
);
~~~

上述，我們建立了兩個外表給 [CLinkPager] 小工具: `default` 和 `classic`。前者是給任何 [CLinkPager] 小工具使用的外表，我們沒有清楚地指定他的 `skin` 屬性，而後者是給指定成 `classic` 的 [CLinkPager] 小工具使用的外表。例如，下述的視圖程式碼，第一個頁碼器會使用 `default` 外表，而第二個會使用 `classic` 外表:

~~~
[php]
<?php $this->widget('CLinkPager'); ?>

<?php $this->widget('CLinkPager', array('skin'=>'classic')); ?>
~~~

如果們建立一個帶有初始化的屬性值的小工具，他們會被優先的整合到任何應用程式的外表。例如，下述的視圖程式碼會建立一個頁碼器，並且被陣列 `array('header'=>'', 'maxButtonCount'=>6, 'cssFile'=>false)` 初始化，這是藉由整合視圖裡初始化屬性值和 `classic` 外表。

~~~
[php]
<?php $this->widget('CLinkPager', array(
    'skin'=>'classic',
    'maxButtonCount'=>6,
    'cssFile'=>false,
)); ?>
~~~

值得注意的是，使用主題時外表功能並不是必需的。然而，當一個主題啟動，Yii 也會搜尋主題資料夾下的 `skins` 資料夾下的外表（例如：`WebRoot/themes/classic/views/skins`）。如果相同名稱的外表同時存在主題和主要應用程式的視圖資料夾，主題的外表會被優先採用。

如果一個小工使用一個不存在的外表，Yii 還是會建立他並且不會產生錯誤。

> Info|提示: 使用外表可能會降低效能因為 Yii 需要搜尋外表的檔案，在一個小工具第一次被建立的時候。

外表功能與全域小工具客製化功能相似。最主要的差別是。

   - 外表與客製化的顯示用的屬性值更有關；
   - 小工具可以有許多外表；
   - 外表可以被主題化；
   - 使用外表比使用全域小工具客製化來的昂貴。

<div class="revision">$Id$</div>